var isMatch = function (s, p) {

    let memo = {}


    let dp = function (s, i, p, j) {
        let m = s.length, n = p.length;

        // base case
        if (j === n) {
            return i === m;
        }

        if (i === m) {
            if ((n - j) % 2 === 1) {
                return false;
            }
            for (; j + 1 < n; j += 2) {
                if (p[j + 1] !== '*') {
                    return false;
                }
            }
            return true;
        }

        // 记录状态（i，j），消除重叠子问题
        let key = i + ',' + j

        if (memo[key] !== undefined) {
            return memo[key];
        }
        let res = false;

        if (s[i] === p[j] || p[j] === '.') {
            // 匹配
            if (j < n - 1 && p[j + 1] === '*') {
                // 1.1 通配符匹配 0 次或多次
                res = dp(s, i, p, j + 2) || dp(s, i + 1, p, j);
            } else {
                // 1.2 常规匹配1次
                res = dp(s, i + 1, p, j + 1);
            }
        } else {
            // 不匹配
            if (j < n - 1 && p[j + 1] === '*') {
                // 2.1 通配符匹配0次
                res = dp(s, i, p, j + 2)
            } else {
                // 2.2 无法继续匹配
                res = false
            }
        }

        // 将当前结果记入备忘录
        memo[key] = res;

        return res;
    }

    // 指针 i，j 从索引 0 开始移动
    return dp(s, 0, p, 0);
};

console.log(isMatch("aa", "a*"))